/*
 * funcionesDeConsola.c
 *
 *  Created on: 20/10/2011
 *      Author: utn_so
 */

#include "funcionesDeConsola.h"

extern t_direccion_fisica posActualCabezal;
extern t_sector *sectorSacado;
extern sem_t sem_trace;
extern sem_t fin_trace;
extern sem_t sem_cola;
extern sem_t sem_sacar;
extern tipoConfigPPD configuracion;
extern t_log* archivoLogueo;

void loguear_planificacion(char *buffer)
{
	if (configuracion.flag)
		log_debug(archivoLogueo, "Sacar", "%s", buffer);
}

void info(int8_t socket, char *buffer)
{

	sprintf(buffer, "La posicion actual del cabezal es %d:%d\n",
			posActualCabezal.cilindro, posActualCabezal.sector);
	enviarAConsola(socket, buffer);
	sprintf(buffer, "----------------- Fin Info ----------------- \n");
	enviarAConsola(socket, buffer);
}

void clean(int8_t socket, char* buffer, uint32_t posInicial, uint32_t posFinal,
		void* var_cola)
{
	uint32_t posActual;
	t_sector *sector;
	sector = (t_sector*) malloc(sizeof(t_sector));
	char *blancos;
	blancos = (char*) malloc(512);
	memset(blancos, '\0', 512);
	sector->type = 4;
	memcpy(sector->datos, blancos, 512);
	sem_wait(&sem_cola);
	for (posActual = posInicial; posActual <= posFinal; posActual++)
	{
		sector->direccion = obtener_dir_fis(posActual);
		if (!strcmp(configuracion.algoritmo, "SSTF"))
			PONER_EN_COLA_SSTF(*sector, (cola) var_cola);
		if (!strcmp(configuracion.algoritmo, "NSTEP"))
			PONER_EN_COLA_NSTEP(*sector, (t_list*) var_cola);
		sem_post(&sem_sacar);
	}
	sem_post(&sem_cola);

	sprintf(buffer, "----------------- Fin Clean ----------------- \n");
	if (send(socket, buffer, strlen(buffer), 0) == -1)
	{
		perror("send");
		exit(1);
	}
}

void enviarAConsola(int8_t socket, char *buffer)
{
	if (send(socket, buffer, strlen(buffer), 0) == -1)
	{
		perror("send");
		exit(1);
	}
}

void planificar(char *buffer, int8_t socket, void *var_cola,
		uint8_t contador_elemento, uint32_t insertados_trace, uint8_t esLogueo)
{
	float tiempoTotal;
	t_direccion_fisica proximo, trace;
	uint8_t j;

	sprintf(buffer, "Posicion actual: %d:%d \n", posActualCabezal.cilindro,
			posActualCabezal.sector);
	if (!esLogueo)
		enviarAConsola(socket, buffer);
	else
		loguear_planificacion(buffer);
	sprintf(buffer, "Sector solicitado: %d:%d \n",
			sectorSacado->direccion.cilindro, sectorSacado->direccion.sector);
	if (!esLogueo)
		enviarAConsola(socket, buffer);
	else
		loguear_planificacion(buffer);
	sprintf(buffer, "Sectores recorridos: ");
	if (!esLogueo)
		enviarAConsola(socket, buffer);
	else
		loguear_planificacion(buffer);

	trace = posActualCabezal;

	if (abs(trace.cilindro - sectorSacado->direccion.cilindro)
			> configuracion.imprimir)
	{
		for (j = 0;
				trace.cilindro < sectorSacado->direccion.cilindro
						&& j <= configuracion.imprimir; j++)
				{
			if (j == (configuracion.imprimir / 2))
			{
				sprintf(buffer, " ... ");
				if (!esLogueo)
					enviarAConsola(socket, buffer);
				else
					loguear_planificacion(buffer);
				trace.cilindro = sectorSacado->direccion.cilindro
						- (configuracion.imprimir / 2);
			}

			trace.cilindro++;
			sprintf(buffer, " %d:%d, ", trace.cilindro, trace.sector);
			if (!esLogueo)
				enviarAConsola(socket, buffer);
			else
				loguear_planificacion(buffer);
		}

		for (j = 0;
				trace.cilindro > sectorSacado->direccion.cilindro
						&& j <= configuracion.imprimir; j++)
				{
			if (j == (configuracion.imprimir / 2))
			{
				sprintf(buffer, " ... ");
				if (!esLogueo)
					enviarAConsola(socket, buffer);
				else
					loguear_planificacion(buffer);
				trace.cilindro = sectorSacado->direccion.cilindro
						- (configuracion.imprimir / 2);
			}

			trace.cilindro--;
			sprintf(buffer, " %d:%d, ", trace.cilindro, trace.sector);
			if (!esLogueo)
				enviarAConsola(socket, buffer);
			else
				loguear_planificacion(buffer);
		}

	}
	else
	{
		while (trace.cilindro < sectorSacado->direccion.cilindro)
		{
			trace.cilindro++;
			sprintf(buffer, " %d:%d, ", trace.cilindro, trace.sector);
			if (!esLogueo)
				enviarAConsola(socket, buffer);
			else
				loguear_planificacion(buffer);
		}

		while (trace.cilindro > sectorSacado->direccion.cilindro)
		{
			trace.cilindro--;
			sprintf(buffer, " %d:%d, ", trace.cilindro, trace.sector);
			if (!esLogueo)
				enviarAConsola(socket, buffer);
			else
				loguear_planificacion(buffer);
		}

	}

	j = 0;
	while (trace.sector != sectorSacado->direccion.sector)
	{
		if (j == (configuracion.imprimir / 2))
		{
			sprintf(buffer, " ... ");
			if (!esLogueo)
				enviarAConsola(socket, buffer);
			else
				loguear_planificacion(buffer);
			trace = restarSectores(sectorSacado->direccion,
					(configuracion.imprimir / 2));
		}

		trace = sumarSectores(trace, 1);
		j++;
		sprintf(buffer, " %d:%d, ", trace.cilindro, trace.sector);
		if (!esLogueo)
			enviarAConsola(socket, buffer);
		else
			loguear_planificacion(buffer);
	}

	tiempoTotal = tiempo_pista(posActualCabezal, sectorSacado->direccion);
	if (!esLogueo)
	{
		sprintf(buffer, "\nTiempo consumido: %fms \n\n", tiempoTotal);
		enviarAConsola(socket, buffer);
	}
	else
	{
		sprintf(buffer, "Tiempo consumido: %fms", tiempoTotal);
		loguear_planificacion(buffer);
	}
	posActualCabezal = sumarSectores(sectorSacado->direccion, 1);
	if (!strcmp(configuracion.algoritmo, "SSTF"))
	{
		if (contador_elemento != insertados_trace)
		{
			proximo = (*(cola) var_cola)->elemento.direccion;
			sprintf(buffer, "Proximo sector: %d:%d \n\n", proximo.cilindro,
					proximo.sector);
			if (!esLogueo)
				enviarAConsola(socket, buffer);
			else
				loguear_planificacion(buffer);
		}
		else
		{
			sprintf(buffer, "Proximo sector: -\n\n");
			if (!esLogueo)
				enviarAConsola(socket, buffer);
			else
				loguear_planificacion(buffer);
			sprintf(buffer, "----------------- Fin Trace -----------------\n");
			if (!esLogueo)
				enviarAConsola(socket, buffer);
		}
	}
	if (!strcmp(configuracion.algoritmo, "NSTEP"))
	{
		if (contador_elemento == insertados_trace)
		{
			sprintf(buffer, "Proximo sector: -\n\n");
			if (!esLogueo)
				enviarAConsola(socket, buffer);
			else
				loguear_planificacion(buffer);
			sprintf(buffer, "----------------- Fin Trace -----------------\n");
			if (!esLogueo)
				enviarAConsola(socket, buffer);
			else
				loguear_planificacion(buffer);
		}
		else
		{
			sprintf(buffer, "Proximo sector: %d:%d \n\n", proximo.cilindro,
					proximo.sector);
			if (!esLogueo)
				enviarAConsola(socket, buffer);
			else
				loguear_planificacion(buffer);
		}

	}

}

void trace(int8_t socket, char* buffer, int32_t *parametros, void* var_cola)
{
	t_sector *sector;
	uint32_t i = 0;
	uint8_t contador_elemento = 0;

	sector = (t_sector*) malloc(sizeof(t_sector));
	sector->type = 3;
	sector->sock = 0;
	memset(sector->datos,'\0',512);

	 // Bloqueo los hilos que sacan e insertan de la cola

	while (parametros[i] != -1 && i < 10)
	{
		sem_wait(&sem_cola);
		sector->direccion = obtener_dir_fis(parametros[i]);

		if (!strcmp(configuracion.algoritmo, "SSTF"))
		{
			PONER_EN_COLA_SSTF(*sector, (cola) var_cola);
		}
		if (!strcmp(configuracion.algoritmo, "NSTEP"))
		{
			PONER_EN_COLA_NSTEP(*sector, (t_list*) var_cola);
		}
		sem_post(&sem_sacar);
		sem_post(&sem_cola);
		i++;
	}

	while (contador_elemento != i)
	{
		sem_wait(&sem_trace);

		contador_elemento++;
		planificar(buffer, socket, var_cola, contador_elemento, i, 0);

		sem_post(&fin_trace);
	}
}

void ver_cola(int8_t socket, void* v_cola, char *buffer, uint8_t esLogueo)
{
	nodo* actual;
	uint32_t sectores_logueados = 0;
	char buffer_logueo[100];
	actual = *((cola) v_cola);
	if (!esLogueo)
	{
		sprintf(buffer, "Cola de pedidos: ");
		enviarAConsola(socket, buffer);
	}
	else
	{
		sprintf(buffer_logueo, "Cola de pedidos: [");
	}
	while (actual != NULL)
	{
		if (!esLogueo)
		{
			sprintf(buffer, " %d:%d, ", actual->elemento.direccion.cilindro,
					actual->elemento.direccion.sector);
			enviarAConsola(socket, buffer);

		}
		else
		{
			if (actual->siguiente == NULL)
			{
				sprintf(buffer_logueo, "%s %d:%d] ",buffer_logueo,
						actual->elemento.direccion.cilindro,
						actual->elemento.direccion.sector);
				sectores_logueados++;
			}
			else
			{
				if (sectores_logueados == cantidadElementos(v_cola) / 2)
				{
					sprintf(buffer_logueo, "%s ... ",buffer_logueo);
				}
				else
				{
					if (sectores_logueados <= configuracion.imprimir)
					{
						sectores_logueados++;
						sprintf(buffer_logueo, "%s %d:%d ",buffer_logueo,
								actual->elemento.direccion.cilindro,
								actual->elemento.direccion.sector);
					}
				}
			}
		}
		actual = actual->siguiente;
	}

	if (!esLogueo)
	{
		sprintf(buffer, "\n----------------- Fin Ver Cola ----------------- \n");
		enviarAConsola(socket, buffer);
	}
	else
	{
		sprintf(buffer_logueo, "%s Tamaño: %d",buffer_logueo, cantidadElementos(v_cola));
		if (configuracion.flag)
			log_debug(archivoLogueo, "Sacar", "%s", buffer_logueo);
	}
}

void interpretar(int8_t socket, char* buffer, char* funcion, void* var_cola)
{

	char *nombreFuncion, *siguienteToken, *actual;
	int32_t parametros[10] =
	{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, i = 0;

	nombreFuncion = strtok_r(funcion, " ", &siguienteToken);

	switch (nombreFuncion[0])
	{
	case ('i'):
		if (!(nombreFuncion[0] == 'i' && nombreFuncion[1] == 'n'
				&& nombreFuncion[2] == 'f' && nombreFuncion[3] == 'o'))
		{
			errorFuncion(buffer, socket);
		}
		else
		{
			info(socket, buffer);
		}
		break;
	case ('c'):
		parametros[0] = atoi(strtok_r(siguienteToken, " ", &siguienteToken));
		parametros[1] = atoi(strtok_r(siguienteToken, " ", &siguienteToken));
		if (!(nombreFuncion[0] == 'c' && nombreFuncion[1] == 'l'
				&& nombreFuncion[2] == 'e' && nombreFuncion[3] == 'a'
				&& nombreFuncion[4] == 'n'))
		{
			errorFuncion(buffer, socket);
		}
		else
		{
			clean(socket, buffer, parametros[0], parametros[1], var_cola);
		}
		break;
	case ('t'):
		if (!(nombreFuncion[0] == 't' && nombreFuncion[1] == 'r'
				&& nombreFuncion[2] == 'a' && nombreFuncion[3] == 'c'
				&& nombreFuncion[4] == 'e'))
		{
			errorFuncion(buffer, socket);
		}
		else
		{
			while (nombreFuncion != NULL)
			{
				actual = siguienteToken;
				nombreFuncion = strtok_r(actual, " ", &siguienteToken);
				if (nombreFuncion != NULL)
				{
					parametros[i] = atoi(nombreFuncion);
				};
				i++;
			};
			trace(socket, buffer, parametros, var_cola);
		}
		break;
	case ('v'):
		if (strcmp(nombreFuncion, "ver\n"))
		{
			errorFuncion(buffer, socket);
		}
		else
		{
			ver_cola(socket, var_cola, buffer, 0);
		}
		break;
	default:
	{
		errorFuncion(buffer, socket);
		break;
	}
	}
}

void errorFuncion(char* buffer, uint8_t socket)
{
	sprintf(buffer, "La funcion no es soportada \n");
	enviarAConsola(socket, buffer);
	sprintf(buffer, "----------------- Fin ----------------- \n");
	enviarAConsola(socket, buffer);
}
